<?php
declare (strict_types=1);

namespace addons\BuilderPlus\components;

use think\helper\Str;

class Compress
{
    private $src;

    private $image;

    private $imageinfo;

    protected $config;

    public function __construct($config)
    {
        $this->config = $config;
    }

    public function image($file): array
    {
        try {
            $file_info = pathinfo($file['file']->getOriginalName());
            $name = md5(Str::random(32)) . '.' . $file_info['extension'];
            $url = $this->config['url'] . date('Ymd') . '/';
            $local = $this->config['local'] . date('Ymd') . '/';
            if (!$this->config['compress']) {
                $result = $file['file']->move($local, $name);
                if (!$this->illegalCheck($url . $result->getFileName())) {
                    throw new \Exception('请勿上传非法文件');
                }

                return ['code' => 1, 'msg' => 'success', 'data' => ['name' => $name, 'url' => $url . $result->getFileName()]];
            } else {
                $this->src = $file['file']->getPathName();
                $this->_openImage();
                if (!file_exists('.' . $url)) mkdir('.' . $url, 0777, true);
                if ($this->_saveImage('.' . $url . $name)) {
                    if (!$this->illegalCheck($url . $name)) {
                        throw new \Exception('请勿上传非法文件');
                    }

                    return ['code' => 1, 'msg' => 'success', 'data' => ['name' => $name, 'url' => $url . $name]];
                } else {
                    throw new \Exception('上传失败');
                }
            }

        } catch (\Exception $e) {

            return ['code' => -1, 'msg' => '上传失败：' . $e->getMessage(), 'data' => ''];
        }

    }

    public function video($file): array
    {
        try {
            $file_info = pathinfo($file['file']->getOriginalName());
            $name = md5(Str::random(32)) . '.' . $file_info['extension'];
            $url = $this->config['url'] . date('Ymd') . '/';
            $local = $this->config['local'] . date('Ymd') . '/';
            $result = $file['file']->move($local, $name);

            return ['code' => 1, 'msg' => 'success', 'data' => ['name' => $name, 'url' => $url . $result->getFileName()]];
        } catch (\Exception $e) {

            return ['code' => -1, 'msg' => '上传失败：' . $e->getMessage(), 'data' => ''];
        }
    }

    public function file($file): array
    {
        try {
            $file_info = pathinfo($file['file']->getOriginalName());
            $name = md5(Str::random(32)) . '.' . $file_info['extension'];
            $url = $this->config['url'] . date('Ymd') . '/';
            $local = $this->config['local'] . date('Ymd') . '/';
            $result = $file['file']->move($local, $name);

            return ['code' => 1, 'msg' => 'success', 'data' => ['name' => $name, 'url' => $url . $result->getFileName()]];
        } catch (\Exception $e) {

            return ['code' => -1, 'msg' => '上传失败：' . $e->getMessage(), 'data' => ''];
        }
    }

    /**
     * @param $disks -- 文件路径
     * @return bool
     * 验证图片是否含有非法文件
     */
    private function illegalCheck($disks): bool
    {
        $file = '.' . $disks;
        if (file_exists($file)) {
            $resource = fopen($file, 'rb');
            $fileSize = filesize($file);
            fseek($resource, 0);

            if ($fileSize > 512) {
                $hexCode = bin2hex(fread($resource, 512));
                fseek($resource, $fileSize - 512);
                $hexCode .= bin2hex(fread($resource, 512));
            } else { // 取全部
                $hexCode = bin2hex(fread($resource, $fileSize));
            }
            fclose($resource);
            $check = preg_match('#__HALT_COMPILER()#i', $hexCode)
                || preg_match('#/script>#i', $hexCode)
                || preg_match('#<([^?]*)\?php#i', $hexCode)
                || preg_match('#<\?\=#i', $hexCode);
            if ($check) {
                $this->error = '非法文件上传！';
                $this->remove($file);
                return false;
            }
            $result = preg_match('/(3c25.*?28.*?29.*?253e)|(3c3f.*?28.*?29.*?3f3e)|(3C534352495054)|(2F5343524950543E)|(3C736372697074)|(2F7363726970743E)/is', $hexCode);
            if ($result) {
                $this->error = '非法文件上传！';
                $this->remove($file);
                return false;
            } else {
                return true;
            }
        } else {
            return false;
        }
    }

    /**
     * @param $disks -- 文件路径
     * @return bool
     * 删除文件
     */
    private function remove($file): bool
    {
        if (file_exists($file)) {
            unlink($file);
            return true;
        } else {
            return false;
        }
    }

    /**
     * 内部：打开图片
     */
    private function _openImage()
    {
        list($width, $height, $type, $attr) = getimagesize($this->src);
        $this->imageinfo = array(
            'width' => $width,
            'height' => $height,
            'type' => image_type_to_extension($type, false),
            'attr' => $attr
        );
        $fun = "imagecreatefrom" . $this->imageinfo['type'];
        $this->image = $fun($this->src);
        $this->_thumpImage();
    }

    /**
     * 内部：操作图片
     */
    private function _thumpImage()
    {
        $new_width = intval($this->imageinfo['width'] * $this->config['percent']);
        $new_height = intval($this->imageinfo['height'] * $this->config['percent']);
        $image_thump = imagecreatetruecolor($new_width, $new_height);
        imagealphablending($image_thump, false); //这里很重要,意思是不合并颜色,直接用$image_thump图像颜色替换,包括透明色;
        imagesavealpha($image_thump, true); //这里很重要,意思是不要丢了$image_thump图像的透明色;
        imagecopyresampled($image_thump, $this->image, 0, 0, 0, 0, $new_width, $new_height, $this->imageinfo['width'], $this->imageinfo['height']);
        imagedestroy($this->image);
        $this->image = $image_thump;
    }

    /**
     * 保存图片到硬盘：
     * @param string $dstImgName 1、可指定字符串不带后缀的名称，使用源图扩展名 。2、直接指定目标图片名带扩展名。
     */
    private function _saveImage($dstImgName)
    {
        if (empty($dstImgName)) return false;
        $allowImgs = ['.jpg', '.jpeg', '.png', '.bmp', '.wbmp', '.gif'];   //如果目标图片名有后缀就用目标图片扩展名 后缀，如果没有，则用源图的扩展名
        $dstExt = strrchr($dstImgName, ".");
        $sourseExt = strrchr($this->src, ".");
        if (!empty($dstExt)) $dstExt = strtolower($dstExt);
        if (!empty($sourseExt)) $sourseExt = strtolower($sourseExt);
        //有指定目标名扩展名
        if (!empty($dstExt) && in_array($dstExt, $allowImgs)) {
            $dstName = $dstImgName;
        } elseif (!empty($sourseExt) && in_array($sourseExt, $allowImgs)) {
            $dstName = $dstImgName . $sourseExt;
        } else {
            $dstName = $dstImgName . $this->imageinfo['type'];
        }
        $funcs = "image" . $this->imageinfo['type'];
        return $funcs($this->image, $dstName);

    }

    /**
     * 销毁图片
     */
    public function __destruct()
    {
        if (!empty($this->config['compress'])) imagedestroy($this->image);
    }
}